//
// Created by root on 4/29/17.
//

#include "../runner_scheme.h"

// (and #t #t) => #t
static void test_op_and_case1() {
    global_scheme->op = cell_op_and0;
    global_scheme->code = LIST_2(&g_true, &g_true);

    ASSERT_OP_CURRENT(and0);
    op_and0(global_scheme);
    EVAL_CODE_AND_RETURN(&g_true, &g_true);

    ASSERT_OP_CURRENT(and1);
    op_and1(global_scheme);
    EVAL_CODE_AND_RETURN(&g_true, &g_true);

    ASSERT_OP_CURRENT(and1);
    op_and1(global_scheme);

    ASSERT_EMPTY_OP_IN_STACK;
}

// (and #t #f) => #f
static void test_op_and_case2() {
    global_scheme->op = cell_op_and0;
    global_scheme->code = LIST_2(&g_true, &g_false);

    ASSERT_OP_CURRENT(and0);
    op_and0(global_scheme);
    EVAL_CODE_AND_RETURN(&g_true, &g_true);

    ASSERT_OP_CURRENT(and1);
    op_and1(global_scheme);
    EVAL_CODE_AND_RETURN(&g_false, &g_false);

    ASSERT_EMPTY_OP_IN_STACK;
}

// (and #t #f) => #f
static void test_op_and_case3() {
    global_scheme->op = cell_op_and0;
    global_scheme->code = LIST_2(&g_false, &g_true);

    ASSERT_OP_CURRENT(and0);
    op_and0(global_scheme);
    EVAL_CODE_AND_RETURN(&g_false, &g_false);

    ASSERT_OP_CURRENT(and1);
    op_and1(global_scheme);

    ASSERT_EMPTY_OP_IN_STACK;
}

// (and #t #f) => #f
static void test_op_and_case4() {
    global_scheme->op = cell_op_and0;
    global_scheme->code = LIST_2(&g_false, &g_false);

    ASSERT_OP_CURRENT(and0);
    op_and0(global_scheme);
    EVAL_CODE_AND_RETURN(&g_false, &g_false);

    ASSERT_OP_CURRENT(and1);
    op_and1(global_scheme);

    ASSERT_EMPTY_OP_IN_STACK;
}


/*
// (or #t #t) => #t
static void test_op_or_case1() {
    global_scheme->op = cell_op_or0;
    global_scheme->code = LIST_2(&g_true, &g_true);

    ASSERT_OP_CURRENT(or0);
    op_or0(global_scheme);
    EVAL_CODE_AND_RETURN(&g_true, &g_true);

    ASSERT_OP_CURRENT(or1);
    op_or1(global_scheme);
    EVAL_CODE_AND_RETURN(&g_true, &g_true);

    ASSERT_OP_CURRENT(or1);
    op_or1(global_scheme);

    ASSERT_EMPTY_OP_IN_STACK;
}

// (and #t #f) => #f
static void test_op_and_case2() {
    global_scheme->op = cell_op_and0;
    global_scheme->code = LIST_2(&g_true, &g_false);

    ASSERT_OP_CURRENT(and0);
    op_and0(global_scheme);
    EVAL_CODE_AND_RETURN(&g_true, &g_true);

    ASSERT_OP_CURRENT(and1);
    op_and1(global_scheme);
    EVAL_CODE_AND_RETURN(&g_false, &g_false);

    ASSERT_EMPTY_OP_IN_STACK;
}

// (and #t #f) => #f
static void test_op_and_case3() {
    global_scheme->op = cell_op_and0;
    global_scheme->code = LIST_2(&g_false, &g_true);

    ASSERT_OP_CURRENT(and0);
    op_and0(global_scheme);
    EVAL_CODE_AND_RETURN(&g_false, &g_false);

    ASSERT_OP_CURRENT(and1);
    op_and1(global_scheme);

    ASSERT_EMPTY_OP_IN_STACK;
}

// (and #t #f) => #f
static void test_op_and_case4() {
    global_scheme->op = cell_op_and0;
    global_scheme->code = LIST_2(&g_false, &g_false);

    ASSERT_OP_CURRENT(and0);
    op_and0(global_scheme);
    EVAL_CODE_AND_RETURN(&g_false, &g_false);

    ASSERT_OP_CURRENT(and1);
    op_and1(global_scheme);

    ASSERT_EMPTY_OP_IN_STACK;
}
*/


static void test_op_or() {
    assert_string_equal(interpret("(or #t #t)"), "#t");
    assert_string_equal(interpret("(or #t #f)"), "#t");
    assert_string_equal(interpret("(or #f #t)"), "#t");
    assert_string_equal(interpret("(or #f #f)"), "#f");
}

static void test_op_not() {
    assert_string_equal(interpret("(not #t)"), "#f");
    assert_string_equal(interpret("(not #f)"), "#t");
}

int main(int argc, char **argv) {
    const struct CMUnitTest tests[] = {
            cmocka_unit_test(test_op_and_case1),
            cmocka_unit_test(test_op_and_case2),
            cmocka_unit_test(test_op_and_case3),
            cmocka_unit_test(test_op_and_case4),

            //cmocka_unit_test(test_op_and),
            //cmocka_unit_test(test_op_or),
            //cmocka_unit_test(test_op_not),
    };
    return cmocka_run_group_tests(tests, setup_scheme, teardown_scheme);
}
